//
//  UIControl+Block.m
//  JSToolkit
//
//  Created by 정재성 on 2013. 11. 10..
//  Copyright (c) 2013년 정재성. All rights reserved.
//

#import "UIControl+Block.h"
#import "NSObject+AssociatedObject.h"

static char kControlHandlersKey;

#pragma mark Private
@interface UIEventHandler : NSObject <NSCopying>

- (id)initWithHandler:(void (^)(id sender))handler forControlEvents:(UIControlEvents)controlEvents;

@property (nonatomic, copy) void (^handler)(id sender);
@property (nonatomic) UIControlEvents controlEvents;

@end

@implementation UIEventHandler

- (id)initWithHandler:(void (^)(id))handler forControlEvents:(UIControlEvents)controlEvents {
	if ((self = [super init])) {
		self.handler = handler;
		self.controlEvents = controlEvents;
	}
	return self;
}

- (id)copyWithZone:(NSZone *)zone {
	return [[UIEventHandler alloc] initWithHandler:self.handler forControlEvents:self.controlEvents];
}

- (void)invoke:(id)sender {
	self.handler(sender);
}

@end

#pragma mark - Category
@implementation UIControl (Block)

- (void)addEventHandler:(void (^)(id))handler forControlEvents:(UIControlEvents)controlEvents
{
    NSParameterAssert(handler);

    NSMutableDictionary *events = [self associatedValueForKey:&kControlHandlersKey];
	if (!events) {
		events = [NSMutableDictionary dictionary];
		[self associateValue:events withKey:&kControlHandlersKey];
	}
	
	NSNumber *key = @(controlEvents);
	NSMutableSet *handlers = events[key];
	if (!handlers) {
		handlers = [NSMutableSet set];
		events[key] = handlers;
	}
	
	UIEventHandler *target = [[UIEventHandler alloc] initWithHandler:handler forControlEvents:controlEvents];
	[handlers addObject:target];
	[self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents];
}

- (void)removeEventHandlersForControlEvents:(UIControlEvents)controlEvents
{
    NSMutableDictionary *events = [self associatedValueForKey:&kControlHandlersKey];
	if (!events) {
		events = [NSMutableDictionary dictionary];
		[self associateValue:events withKey:&kControlHandlersKey];
	}
	
	NSNumber *key = @(controlEvents);
	NSSet *handlers = events[key];
    
	if (!handlers)
		return;

	[handlers enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
        [self removeTarget:obj action:NULL forControlEvents:controlEvents];
    }];
	
	[events removeObjectForKey:key];
}

- (BOOL)hasEventHandlersForControlEvents:(UIControlEvents)controlEvents
{
    NSMutableDictionary *events = [self associatedValueForKey:&kControlHandlersKey];
	if (!events) {
		events = [NSMutableDictionary dictionary];
		[self associateValue:events withKey:&kControlHandlersKey];
	}
	
	NSNumber *key = @(controlEvents);
	NSSet *handlers = events[key];
	
	if (!handlers)
		return NO;
	
	return handlers.count;
}

@end
